#!/usr/bin/env python
# Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights
# reserved. Use of this source code is governed by a BSD-style license
# that can be found in the LICENSE file.
"""
A simple utility function to merge pack resource files into a single resource file.
"""

from __future__ import absolute_import
from __future__ import print_function
from cef_parser import get_copyright
from file_util import *
import os
import re
import string
import sys


def _make_pack_header_segment(input, ids):
  result = """

// ---------------------------------------------------------------------------
// From $FILE$:
"""

  filename = os.path.split(input)[1]
  result = result.replace('$FILE$', filename)

  for name, id in ids.items():
    result += "\n#define %s %s" % (name, id)

  return result


def make_pack_header(output, all_files):
  # header string
  result = get_copyright(full=True, translator=False) + \
"""//
// ---------------------------------------------------------------------------
//
// This file is generated by the make_pack_header.py tool.
//

#ifndef $GUARD$
#define $GUARD$
#pragma once"""

  # generate the file segments
  for file, ids in all_files.items():
    result += _make_pack_header_segment(file, ids)

  # footer string
  result += \
"""

#endif  // $GUARD$
"""

  # add the guard string
  filename = os.path.split(output)[1]
  guard = 'CEF_INCLUDE_' + filename.replace('.', '_').upper() + '_'
  result = result.replace('$GUARD$', guard)

  return result


def _get_cpp_var_name(output):
  filename_no_ext = os.path.splitext(os.path.split(output)[1])[0]

  # Convert to CamelCase after removing the 'cef_' prefix.
  parts = filename_no_ext.split('_')[1:]
  return "".join([p[0].upper() + p[1:] for p in parts])


def make_pack_inc(output, all_files):
  var = 'IdNames' + _get_cpp_var_name(output)

  result = get_copyright(full=False, translator=False) + \
"""//
// ---------------------------------------------------------------------------
//
// This file was generated by the make_pack_header.py tool.
//

namespace {

struct $var$ {
  int id;
  const char* const name;
};

const $var$ k$var$[] = {""".replace('$var$', var)

  for file, ids in all_files.items():
    result += '\n  // From %s:' % file
    for name, id in ids.items():
      result += '\n  {%s, "%s"},' % (id, name)

  result += \
"""
};

const size_t k$var$Size = std::size(k$var$);

}  // namespace
""".replace('$var$', var)

  return result


def _get_defines(input, all_names):
  contents = read_file(input)

  ids = {}

  # Format for Windows builds with resource whitelisting enabled [1]:
  #   #define IDR_RESOURCE_NAME (::ui::WhitelistedResource<12345>(), 12345)
  # Format for other builds:
  #   #define IDR_RESOURCE_NAME 12345
  # [1] See https://crbug.com/684788#c18

  regex = r'#define\s([A-Za-z0-9_]{1,})\s+'
  if contents.find('ui::WhitelistedResource') > 0:
    regex += r'.*<'
  regex += r'([0-9]{1,})'

  # identify the defines in the file
  p = re.compile(regex)
  list = p.findall(contents)
  for name, id in list:
    # If the same define exists in multiple files add a suffix.
    if name in all_names:
      all_names[name] += 1
      name += '_%d' % all_names[name]
    else:
      all_names[name] = 1

    ids[name] = id

  return ids


def write_pack_header(out_header_file, out_inc_file, inputs):
  # sort the input files by name
  inputs = sorted(inputs, key=lambda path: os.path.split(path)[1])

  all_names = {}
  all_files = {}

  # generate the file segments
  for file in inputs:
    filename = os.path.split(file)[1]
    assert not filename in all_files, filename
    all_files[filename] = _get_defines(file, all_names)

  out_file = os.path.abspath(out_header_file)
  result = make_pack_header(out_file, all_files)
  if not bool(result):
    sys.stderr.write('Failed to create %s\n' % out_file)
    sys.exit(1)
  retval1 = write_file_if_changed(out_file, result)

  out_file = os.path.abspath(out_inc_file)
  result = make_pack_inc(out_file, all_files)
  if not bool(result):
    sys.stderr.write('Failed to create %s\n' % out_file)
    sys.exit(1)
  retval2 = write_file_if_changed(out_file, result)

  return retval1  #or retval2


def main(argv):
  if len(argv) < 4:
    print(
        "Usage:\n  %s <output_header_file> <output_inc_file> <input_file1> [input_file2] ... "
        % argv[0])
    sys.exit(-1)
  write_pack_header(argv[1], argv[2], argv[3:])


if '__main__' == __name__:
  main(sys.argv)
